﻿using System.Windows.Input;
using System.Windows.Media;
using KinonekoSoftware.Foundation;
using KinonekoSoftware.Foundation.Patterns;
using KinonekoSoftware.Platform.Windows;

namespace KinonekoSoftware.Platform.Controls
{
    public sealed class WindowStateObserver : ObservableObject
    {
        private        WindowState         _windowState;
        private static WindowStateObserver _instance;

        public static WindowStateObserver Instance
        {
            get
            {
                _instance ??= new WindowStateObserver();
                return _instance;
            }
        }

        /// <summary>
        /// 获取或设置 <see cref="WindowState"/> 属性。
        /// </summary>
        public WindowState WindowState
        {
            get => _windowState;
            set => SetValue(ref _windowState, value);
        }
    }
    
    public abstract class ForestWindow : Window
    {
        public static readonly DependencyProperty ExtendToTitleBarProperty;
        public static readonly DependencyProperty TitleBarProperty;
        public static readonly DependencyProperty TitleBarTemplateProperty;
        public static readonly DependencyProperty TitleBarTemplateSelectorProperty;
        public static readonly DependencyProperty TitleBarStringFormatProperty;
        public static readonly DependencyProperty TitleBarBrushProperty;
        
        static ForestWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ForestWindow), new FrameworkPropertyMetadata(typeof(ForestWindow)));
            ExtendToTitleBarProperty = DependencyProperty.Register(
                nameof(ExtendToTitleBar),
                typeof(bool),
                typeof(ForestWindow),
                new PropertyMetadata(Boxing.True));
            
            TitleBarProperty = DependencyProperty.Register(
                nameof(TitleBar),
                typeof(object),
                typeof(ForestWindow),
                new PropertyMetadata(default(object)));
            
            TitleBarTemplateProperty = DependencyProperty.Register(
                nameof(TitleBarTemplate),
                typeof(DataTemplate),
                typeof(ForestWindow),
                new PropertyMetadata(default(DataTemplate)));
            
            TitleBarTemplateSelectorProperty = DependencyProperty.Register(
                nameof(TitleBarTemplateSelector),
                typeof(DataTemplateSelector),
                typeof(ForestWindow),
                new PropertyMetadata(default(DataTemplateSelector)));
            
            TitleBarStringFormatProperty = DependencyProperty.Register(
                nameof(TitleBarStringFormat),
                typeof(string),
                typeof(ForestWindow),
                new PropertyMetadata(default(string)));
            
            TitleBarBrushProperty = DependencyProperty.Register(
                nameof(TitleBarBrush),
                typeof(Brush),
                typeof(ForestWindow),
                new PropertyMetadata(default(Brush)));
            WindowStateProperty.AddOwner(typeof(ForestWindow))
                               .OverrideMetadata(typeof(ForestWindow), new FrameworkPropertyMetadata(OnWindowStateChanged));
        }

        private static void OnWindowStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var w = (ForestWindow)d;
            w.OnWindowStateChangedIntern(d, (WindowState)e.NewValue);
        }
        
        protected ForestWindow()
        {
            //
            // Event
            Loaded   += OnLoaded;
            Unloaded += OnUnloaded;

            //
            //
            CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, OnWindowClose));
            CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, OnWindowMinimum));
            CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, OnWindowRestore));
            CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, OnWindowRestore));
            
            //
            //
            Initialize();
        }

        #region WindowState

        private void OnWindowStateChangedIntern(object sender, WindowState e)
        {
            WindowStateObserver.Instance.WindowState = e;
            OnWindowStateChanged(sender, e);
            WindowStateChanged?.Invoke(sender, e);
        }

        protected virtual void OnWindowStateChanged(object sender, WindowState e)
        {
            
        }

        #endregion

        #region OnUnloaded / OnLoaded

        
        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            //
            //
            Loaded   -= OnLoaded;
            Unloaded -= OnUnloaded;

            Ioc.Get<ShellCore>().Stop();

            //
            //
            OnUnloadedInternal();
            OnUnloaded();
        }

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            var app = Application.Current as WindowsApplication;

            //
            //
            DataContext = app?.FrameworkInitializationCompleted();

            //
            //
            OnLoadedInternal();
            OnLoaded();
        }
        
        
        internal virtual void OnLoadedInternal()
        {
        }

        internal virtual void OnUnloadedInternal()
        {

        }

        protected virtual void OnLoaded()
        {

        }

        protected virtual void OnUnloaded()
        {

        }

        #endregion


        protected T ViewModel<T>() where T : class
        {
            return DataContext as T;
        }

        #region Initialize

        

        private void Initialize()
        {
            OnApplyStyle();
        }

        protected virtual void OnApplyStyle()
        {
            Style ??= Application.Current.Resources[nameof(ForestWindow)] as Style;
        }
        
        #endregion

        #region SystemCommands

        private async  void OnWindowClose(object sender, ExecutedRoutedEventArgs e)
        {
            if (await CanClose())
            {
                Close();
            }
        }

        protected virtual  Task<bool> CanClose() => Task.FromResult(true);

        private void OnWindowMinimum(object sender, ExecutedRoutedEventArgs e)
        {
            if(ResizeMode == ResizeMode.NoResize)
            {
                return;
            }

            WindowState = WindowState.Minimized;
        }

        private void OnWindowRestore(object sender, ExecutedRoutedEventArgs e)
        {
            if (ResizeMode == ResizeMode.NoResize)
            {
                return;
            }

            WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
        }

        #endregion SystemCommands


        /// <summary>
        /// 获取或设置 <see cref="TitleBarStringFormat"/> 属性。
        /// </summary>
        public Brush TitleBarBrush
        {
            get => (Brush)GetValue(TitleBarBrushProperty);
            set => SetValue(TitleBarBrushProperty, value);
        }

        /// <summary>
        /// 获取或设置 <see cref="TitleBarStringFormat"/> 属性。
        /// </summary>
        public string TitleBarStringFormat
        {
            get => (string)GetValue(TitleBarStringFormatProperty);
            set => SetValue(TitleBarStringFormatProperty, value);
        }

        /// <summary>
        /// 获取或设置 <see cref="TitleBarTemplateSelector"/> 属性。
        /// </summary>
        public DataTemplateSelector TitleBarTemplateSelector
        {
            get => (DataTemplateSelector)GetValue(TitleBarTemplateSelectorProperty);
            set => SetValue(TitleBarTemplateSelectorProperty, value);
        }

        /// <summary>
        /// 获取或设置 <see cref="TitleBarTemplate"/> 属性。
        /// </summary>
        public DataTemplate TitleBarTemplate
        {
            get => (DataTemplate)GetValue(TitleBarTemplateProperty);
            set => SetValue(TitleBarTemplateProperty, value);
        }

        /// <summary>
        /// 获取或设置 <see cref="TitleBar"/> 属性。
        /// </summary>
        public object TitleBar
        {
            get => GetValue(TitleBarProperty);
            set => SetValue(TitleBarProperty, value);
        }
        
        public bool ExtendToTitleBar
        {
            get => (bool)GetValue(ExtendToTitleBarProperty);
            set => SetValue(ExtendToTitleBarProperty, Boxing.Box(value));
        }
        public event EventHandler<WindowState> WindowStateChanged;
    }
}